package com.test.springboot_test.test02_LambdaAndStream.domain;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
          test06();
//        test05();
//            test04();
        test05();
//            test04();
//          test03();
//        test02();
       // test01(authors);
    }

    private static void test05() {
        //stream流的终结操作-reduce
        //reduce归并：对流中的数据按照你指定的一种计算方式计算出一种计算结果（缩减操作）
        //reduce的作用是把stream流中的元素组合起来，我们可以传入一个初始值，
        // 他会按照我们的计算方式一次拿流中的元素和在初始值的基础上进行计算，计算结果在和后面的元素计算
        List<Author> authors = getAuthors();
        Optional<Integer> reduce = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce((a, b) -> a + b);
        System.out.println(reduce.get());
        System.out.println("--------------------------------");
        //使用reduce求作者中年龄最大的值
        Integer min = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element);
        System.out.println(min);
        System.out.println("---------------------------------");
        //使用reduce求作者中年龄最小的值--这里用的是两个参数
        Integer max = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result > element ? result : element);
        System.out.println(max);
        System.out.println("-----------------------------");

        //使用reduce求作者中年龄最小的值--这里用的是一个参数
        Optional<Integer> minOptional = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce((result, element) -> result < element ? result : element);
        minOptional.ifPresent(System.out::println);
        System.out.println("------------------------------");

        //注意事项
        //1.惰性求值（如果没有终结操作-中间操作是不会执行的）
        Integer [] arr = {1,2,3,4,5,6};//这里我没用集合，我用的是数组做测试
        Stream<Integer> stream = Arrays.stream(arr);//将数组转换成流
        Stream<Integer> integerStream = stream.map(a -> a * a);//我在这里做一步中间操作，不做终结操作
        integerStream.forEach(System.out::println);//我这里输出，可以正常输出----所以惰性求值-我觉得并不完全成立
        System.out.println("===========================");
        //2.流是一次性的（一旦一个对象经过一个终结操作后。这个流就不能在使用）
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(2);
        arrayList.add(6);
        //这里是创建了两个不一样的流
        arrayList.stream()//第一次使用流
                .filter(element -> element % 2 == 0)
                .forEach(System.out::println);
        arrayList.stream()//第二次使用流
                .filter(element -> element % 2 == 1)
                .forEach(System.out::println);
        System.out.println("==========================");
        //换一种测试
        Stream<Integer> stream1 = arrayList.stream();//将集合转换成流
        //同一种流使用两次，会出现报错
        stream1.filter(a->a>2).forEach(System.out::println);//第一次使用流
        //stream1.filter(a->a>2).forEach(System.out::println);//第二次使用流
        System.out.println("==========================");

        //注意事项3：不会影响原数据（我们在流中可以多数据做很多处理，但是正常情况下，不会影响原集合数据的）
        //用数组转换流的第二种形式
        Integer [] arr1 = {1,2,3,4,5,6};
        Stream<Integer> arr2 = Stream.of(arr1);//将数组转换成流
        arr2.filter(element -> element % 2 == 0)
                .forEach(System.out::println);//对流的数据进行打印--过滤后打印
        System.out.println("----");
        Arrays.stream(arr1).forEach(System.out::println);//直接打印
        System.out.println("==========================");

    }


    private static void test06() {
        //终端操作
        //输出作家的姓名
        getAuthors().stream()
                .map(author -> author.getName())
                .distinct()
                .forEach(name->System.out.println(name));
        System.out.println("--------------------------------");
        //测试count 统计流当中的个数
        //打印这些作家的所出书籍的数目，注意剔除重复元素
        long count = getAuthors().stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
        System.out.println("-----------------------");
        //求最值max/min
        //分别获取这些作家所出书籍的最高分和最低分并打印
        Optional<Integer> max = getAuthors().stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(book -> book.getScore())
                .max((o1, o2) -> o1 - o2);
        System.out.println("max最大值"+max);
        Optional<Integer> min = getAuthors().stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(book -> book.getScore())
                .min((o1, o2) -> o1 - o2);
        System.out.println(min.get());
        System.out.println("测试最小值----------------------");
        //获取一个存放作者名字的list集合
        List<Author> authors = getAuthors();
        List<String> nameList = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(nameList);
        System.out.println("------------------------------------");
        //获取一个所有书名的Set集合
        Set<Book> set = getAuthors().stream()
                .flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(set);
        System.out.println("-------------------------------------");
        //获取一个map集合，map的key为作者名，value为List<Book>
        Map<String, List<Book>> listMap = getAuthors().stream().distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(listMap);
        System.out.println("-----------------------------------");
        //测试查找与匹配-anyMatch-任意有一个匹配就可以
        //判断是否有29岁以上的作家
        boolean b = getAuthors().stream()
                .map(author -> author.getAge())
                .distinct()
                .anyMatch(age -> age > 46);
        System.out.println(b);
        System.out.println("---------------------------------");
        //allMatch-所有的匹配-结果是true
        //所有的作家都是成年人
        boolean b1 = getAuthors().stream()
                .distinct()
                .map(author -> author.getAge())
                .allMatch(age -> age > 1);
        System.out.println("b1:"+b1);
        System.out.println("------------------------");
        //nomatch-里面所有的元素都不满足
        //判断作家的年纪都没有超过100
        boolean b2 = getAuthors().stream()
                .noneMatch(author -> author.getAge() >= 100);
        System.out.println("b2:"+b2);
        System.out.println("----------------------------");

        //findAny(),获取流中任意一个元素
        //获取任意一个年龄大于18的作家，如果存在就输出他的名字
        Optional<Author> optionalAuthor = getAuthors().stream()
                .filter(author -> author.getAge() > 18)
                .findAny();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
        System.out.println("---------------------------");
        //测试findFirst - 查询流中的第一个元素
        //获取一个年龄最小的作家，并输出他的名字
        Optional<Author> firstOptional = getAuthors().stream()
                .sorted(((o1, o2) -> o1.getAge() - o2.getAge()))
                .distinct()
                // .forEach(author -> System.out.println(author.getAge()));
                .findFirst();
        firstOptional.ifPresent(author -> System.out.println(author.getAge()));


    }

    private static void test05_1() {
        //复盘：创建流的三种形式
        //1.集合
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
        stream.distinct()
                .filter(author -> author.getAge() < 40)
                .map(author -> author.getAge())
                .sorted(((o1, o2) -> o1 - o2))
                .limit(2)
                .skip(1)
                .forEach(age->System.out.println(age));
        System.out.println("复盘1-------------------------");
        //2.数组的两种形式-1
        Integer arr[] = {1,2,3,4,5,6,7,1,2,3,4};
        Stream<Integer> stream1 = Arrays.stream(arr);
        stream1.sorted(((o1, o2) -> o2 - o1))
                .limit(2)
                .forEach(a->System.out.println(a));
        System.out.println("数组的两种形式-1---------------------");
        //2.数组的两种形式-2
        Integer arr2[] = {2,3,4,5,6,1,7,8};
        Stream<Integer> arr3 = Stream.of(arr2);
        arr3.sorted((o1, o2) -> o2 - o1)
                .limit(6)
                .skip(3)
                .forEach(a->System.out.println(a));
        System.out.println("数组的两种形式-2");
        //3.转换为双列集合
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1,"蜡笔小新");
        map.put(2,"海贼王");
        map.put(3,"火影忍者");
        Stream<Map.Entry<Integer, String>> stream2 = map.entrySet().stream();
        stream2.forEach(entry->{
            System.out.println(entry.getKey() + "===" + entry.getValue());
        });
        System.out.println("双列集合===============");
        //测试flatmap
        getAuthors().stream()
                .flatMap(author -> author.getBooks().stream())
                .flatMap(book->Stream.of(book.getCaregory().split(",")))
                .distinct()
                .forEach(caregory->System.out.println(caregory));
        System.out.println("测试完毕2025-5-14");
    }

    private static void test04() {
        //stream流的中间操作

        List<Author> authors = getAuthors();
        //测试    过滤filter+去重distinct
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(author -> {
            System.out.println(author.getName());
        });
        System.out.println("测试filter+去重");
        //测试map 转换对象，将原先的author对象转换成其中的某一列
        authors.stream()
                .map(author -> author.getName())
                .forEach(name -> System.out.println(name));
        System.out.println("测试map 转换对象，将原先的author对象转换成其中的某一列");
        //测试sorted

        //1.无参的sorted（），直接使用会报错。类转换异常:Exception in thread "main" java.lang.ClassCastException
        //解决办法：需要去实现Comparable类
        authors.stream()
                .distinct()
                .sorted()//
                .forEach(author -> {
                    System.out.println(author.getAge());
                });
        System.out.println("无参数但进行配置的sorted");
        //有参数但无需配置的sorted（），
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .forEach(author -> {
                    System.out.println(author.getAge());
                });
        System.out.println("有参数但无需配置的sorted");
        //降序，测试limit，找出年纪最大的两个
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .limit(2)
                .forEach(author -> {
                    System.out.println(author.getAge());
                });
        System.out.println("降序，测试limit，找出年纪最大的两个");

        //排除，skip：给出案例要求：按照年龄降序，剔除最大的一个
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .limit(2)
                .skip(1)
                .forEach(author -> {
                    System.out.println(author.getAge());
                });
        //测试案例1：flatmap，一个对象转换成多个对象，要和map区分开
        //打印所有书籍的名字，要求对重复元素去重
        //我对map的理解：一个对象多个元素，经map转换成一个对象元素
        //我对flatmap的理解：一个对象->转换成一个属性对象->把若单个属性对象是集合，把集合转换成流对象
        authors.stream()
                .flatMap(author -> {
                    return author.getBooks().stream();
                })
                .distinct()
                .forEach(
                        book -> {
                            System.out.println(book.getName());
                        }
                );
        System.out.println("测试案例1：flatmap，一个对象转换成多个对象，要和map区分开");
        //案例2：打印现有数据库的所有分类。要求对分类去重。不能出现这种格式：哲学,爱情
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCaregory().split(",")))//数组转化成流对象
                .distinct()
                .forEach(caregory -> System.out.println(caregory));
        System.out.println("案例2：打印现有数据库的所有分类。要求对分类去重。不能出现这种格式：哲学,爱情");
    }

    private static void test03() {
        //创建流的三种方式-单项列表-数组-双向列表
        //单项列表
        ArrayList<Object> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Stream<Object> stream = list.stream();
        stream.forEach(System.out::println);
        System.out.println("单项列表");

        //数组
        Integer arr[]={1,2,3,4,5,6,7};
        //用集合的方式进行转化
        Stream<Integer> stream1 = Arrays.stream(arr);
        stream1.forEach(System.out::println);
        System.out.println("用集合的方式将数组转化成流");
        //用Stream工具包的形式进行转化
        Stream<Integer> arr1 = Stream.of(arr);
        arr1.forEach(System.out::println);
        System.out.println("用stream工具包的方式进行转化");

        //双向列表
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1,"蜡笔小新");
        map.put(2,"海贼王");
        map.put(3,"火影忍者");
        Stream<Map.Entry<Integer, String>> stream2 = map.entrySet().stream();
        stream2.forEach(entry -> System.out.println(entry.getKey() + ":" + entry.getValue()));
        System.out.println("双向列表");
    }

    private static void test02() {

        //常用操作--创建流
        //1.用集合
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Stream<Integer> stream = list.stream();
        stream.forEach(System.out::println);
        System.out.println();
        //2.用数组
        Integer arr[]={1,2,3,4,5,6,7};
        //用集合的方法进行转化Arrays.stream()
        Stream<Integer> stream1 = Arrays.stream(arr);
        stream1.forEach(System.out::println);
        System.out.println();
        //用数组的方式进行转化，用Stream这个工具包
        Stream<Integer> arr1 = Stream.of(arr);
        arr1.forEach(System.out::println);
        System.out.println("双向列表");
        //3.双向列表
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1,"蜡笔小新");
        map.put(2,"萤火虫");
        map.put(3,"火影忍者");
        Stream<Map.Entry<Integer, String>> entryStream = map.entrySet().stream();
        entryStream.forEach(entry -> {
            String s = entry.getKey() + entry.getValue();
            System.out.println(s);
        });


    }

    private static void test01(List<Author> authors) {
        //这个是匿名内部类的形式
        authors.stream()//将对象转化成流
                .distinct()//去重
                .filter(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() < 18;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
        System.out.println("-------------------------------------------");
        //lambda形式
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(auhtor -> System.out.println(auhtor.getName()));
    }


    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));

        books2.add(new Book(1L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难嘛"));

        books3.add(new Book(5L,"刀的两侧是是光明与黑暗","爱情",56,"用一把刀划分了爱恨"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> list = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return list;

    }


}
